package com.cbs.android.component.network;

import com.cbs.android.component.log.L;
import com.cbs.android.component.network.decoder.Decoder;

import java.io.IOException;
import java.util.List;

import okhttp3.Headers;
import okhttp3.ResponseBody;

/**
 * Created by brochexu on 9/2/14.
 */
public class Response {
    private static final String TAG = Response.class.getName();
    private Request request = null;
    private okhttp3.Response rawResponse = null;
    private Response networkResponse = null;
    private Response cacheResponse = null;
    private Object result = null;

    public Response(okhttp3.Response rawResponse, Request request) {
        this.rawResponse = rawResponse;
        this.request = request;

        result = getResponseResult(rawResponse, request.getDecoder());
        if (rawResponse.networkResponse() != null) {
            networkResponse = new Response(rawResponse.networkResponse(), request);
        }
        if (rawResponse.cacheResponse() != null) {
            cacheResponse = new Response(rawResponse.cacheResponse(), request);
        }
    }

    /**
     * The wire-level request that initiated this HTTP response. This is not
     * necessarily the same request issued by the application:
     * <ul>
     * <li>It may be transformed by the HTTP client. For example, the client
     * may copy headers like {@code Content-Length} from the request body.
     * <li>It may be the request generated in response to an HTTP redirect or
     * authentication challenge. In this case the request URL may be
     * different than the initial request URL.
     * </ul>
     */
    public Request getRequest() {
        return request;
    }

    /**
     * Returns the HTTP status code.
     */
    public int getCode() {
        return rawResponse.code();
    }

    /**
     * Returns true if the code is in [200..300), which means the request was
     * successfully received, understood, and accepted.
     */
    public boolean isSuccessful() {
        return rawResponse.isSuccessful();
    }

    /**
     * Returns the HTTP status message or null if it is unknown.
     */
    public String getMessage() {
        return rawResponse.message();
    }

    public List<String> getHeaders(String name) {
        return rawResponse.headers(name);
    }

    public String getHeader(String name) {
        return getHeader(name, null);
    }

    public String getHeader(String name, String defaultValue) {
        return rawResponse.header(name, defaultValue);
    }

    public Headers getHeaders() {
        return rawResponse.headers();
    }

    public Object getResult() {
        return result;
    }

    public Response getNetworkResponse() {
        return networkResponse;
    }

    public Response getCacheResponse() {
        return cacheResponse;
    }

    /**
     * Returns true if this response redirects to another resource.
     */
    public boolean isRedirect() {
        return rawResponse.isRedirect();
    }

    public boolean isCache() {
        return networkResponse == null;
    }

    @Override
    public String toString() {
        return rawResponse.toString();
    }

    public okhttp3.Response getRawResponse() {
        return rawResponse;
    }

    public String desc() {
        if (result != null) {
            if (request != null && request.getDecoder() != null) {
                return request.getDecoder().desc(result);
            } else {
                return result.toString();
            }
        } else {
            return "";
        }
    }

    private Object getResponseResult(okhttp3.Response response, Decoder decoder) {
        Object result = null;
        if (response == null) {
            return result;
        }
        ResponseBody body = response.body();
        if (body == null) {
            return result;
        }
        if (response.isSuccessful()) {
            try {
                result = decoder.decode(body);
            } catch (IOException e) {
                L.w(TAG, "", e);
                return result;
            }
        } else {
            try {
                result = body.string();
            } catch (IOException e) {
                L.w(TAG, "", e);
                return result;
            }
        }
        body.close();
        return result;
    }
}
